import * as THREE from 'three'

export const createParametricGeometry = (
  fn: (u: number, v: number) => number[],
  resolution = 50,
) => {
  const bufferGeometry = new THREE.BufferGeometry()
  const vertices: number[] = []
  const indices: number[] = []
  const normals: number[] = []
  const uvs: number[] = []

  // 生成顶点数据
  for (let i = 0; i <= resolution; i++) {
    const u = i / resolution
    for (let j = 0; j <= resolution; j++) {
      const v = j / resolution
      const [x, y, z] = fn(u, v)

      // 动态计算法线
      const epsilon = 0.001
      const [dx1, dy1, dz1] = fn(u + epsilon, v)
      const [dx2, dy2, dz2] = fn(u, v + epsilon)

      const tangent = new THREE.Vector3(dx1 - x, dy1 - y, dz1 - z)
      const bitangent = new THREE.Vector3(dx2 - x, dy2 - y, dz2 - z)
      const normal = new THREE.Vector3()
        .crossVectors(tangent, bitangent)
        .normalize()

      vertices.push(x, y, z)
      normals.push(normal.x, normal.y, normal.z)
      uvs.push(u, v)
    }
  }

  // 生成索引数据
  for (let i = 0; i < resolution; i++) {
    for (let j = 0; j < resolution; j++) {
      const a = i * (resolution + 1) + j
      const b = a + 1
      const c = a + resolution + 1
      const d = c + 1

      indices.push(a, c, b)
      indices.push(b, c, d)
    }
  }

  // 设置几何体属性
  bufferGeometry.setAttribute(
    'position',
    new THREE.Float32BufferAttribute(vertices, 3),
  )
  bufferGeometry.setAttribute(
    'normal',
    new THREE.Float32BufferAttribute(normals, 3),
  )
  bufferGeometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2))
  bufferGeometry.setIndex(indices)

  return bufferGeometry
}

export const disposeGeometry = (geometry: THREE.BufferGeometry) => {
  if (geometry) {
    geometry.dispose()
    // @ts-ignore
    geometry.attributes = null
    geometry.index = null
  }
}
